package com.example.patient.service.impl;

import cn.hutool.core.date.DateUtil;
import com.example.common.entity.*;
import com.example.common.support.ApiException;
import com.example.common.utils.IdUtils;
import com.example.common.utils.SmsUtils;
import com.example.common.vo.WxSubScribeMessageVo;
import com.example.common.vo.WxTemplateMessageVo;
import com.example.patient.jpa.*;
import com.example.patient.properties.WxProp;
import com.example.patient.service.WXPayService;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants.WxpayTradeStatus;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import com.example.common.sendhttp.WxSendMessage;

/**
 * @Author wxy
 * @Date 2021/1/18 10:52
 * @Version 1.0
 */
@Service
public class WXPayServiceImpl implements WXPayService {
    @Resource
    private WxProp wxProp;
    @Resource
    private HttpServletRequest request;

    @Resource
    private OnlineConsultationRepository onlineConsultationRepository;
    @Resource
    private OrderMainRepository orderMainRepository;
    @Resource
    private ExInfoRepository exInfoRepository;
    @Resource
    private ConfigRepository configRepository;
    @Resource
    private DrAndPatientsRepository drAndPatientsRepository;
    @Resource
    private DoctorBaseInfoRepository doctorBaseInfoRepository;
    @Resource
    private EnumConfigRepository enumConfigRepository;
    @Resource
    private MsgConfigRepository msgConfigRepository;
    @Resource
    private RxMainRepository rxMainRepository;
    @Resource
    private ClientBaseInfoRepository clientBaseInfoRepository;
    @Resource
    private HospitalDepartmentRepository hospitalDepartmentRepository;
    @Resource
    private PatientsInfoRepository patientsInfoRepository;
    @Resource
    private PlantOrderRepository plantOrderRepository;
    @Resource
    private WxSendMessage wxSendMessage;
    

    /**
     * 微信支付回调（公众号）
     */
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public Object CallBack() {
        WxPayService wxPayService = new WxPayServiceImpl();
        WxPayConfig wxPayConfig = new WxPayConfig();
        wxPayConfig.setAppId(wxProp.getWxPublicAppId());
        wxPayConfig.setMchId(wxProp.getMchId());
        wxPayConfig.setMchKey(wxProp.getMchKey());
        wxPayService.setConfig(wxPayConfig);
        Boolean bool = analysisWxResultXml(wxPayService);
        if (bool) {
            return WxPayNotifyResponse.success("处理成功！");
        }
        return null;
    }

    /**
     * 微信支付回调(小程序)
     */
    @Override
    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public Object CallBackWa() {
        WxPayService wxPayService = new WxPayServiceImpl();
        WxPayConfig wxPayConfig = new WxPayConfig();
        wxPayConfig.setAppId(wxProp.getWxAppletsAppId());
        wxPayConfig.setMchId(wxProp.getMchId());
        wxPayConfig.setMchKey(wxProp.getMchKey());
        wxPayService.setConfig(wxPayConfig);
        Boolean bool = analysisWxResultXml(wxPayService);
        if (bool) {
            return WxPayNotifyResponse.success("处理成功！");
        }
        return null;
    }

    @Override

    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public Object CallBackTest(String orderNo) {
        String transactionNo = "" + IdUtils.generateId();
        if (orderNo.contains("MP")) {
            MPOrderHandle(orderNo, transactionNo);
        } else if (orderNo.contains("RX") || orderNo.contains("RZ")) {
            return RxOrderHandle(orderNo, transactionNo);
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public Boolean analysisWxResultXml(WxPayService wxPayService) {
        WxPayOrderNotifyResult wxPayOrderNotifyResult;
        try {
            String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            wxPayOrderNotifyResult = wxPayService.parseOrderNotifyResult(xmlResult);
        } catch (IOException | WxPayException e) {
            throw new ApiException(1, e.getMessage());
        }
        String resultCode = wxPayOrderNotifyResult.getResultCode();
        if ("SUCCESS".equals(resultCode)) {
            String orderNo = wxPayOrderNotifyResult.getOutTradeNo();
            String transactionNo = wxPayOrderNotifyResult.getTransactionId();
            if (orderNo.contains("MP")) {
                return MPOrderHandle(orderNo, transactionNo);
            } else if (orderNo.contains("RX") || orderNo.contains("RZ")) {
                return RxOrderHandle(orderNo, transactionNo);
            } else {
                return Boolean.FALSE;
            }
        }
        return Boolean.FALSE;
    }

    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public Boolean MPOrderHandle(String orderNo, String transactionNo) {
        OnlineConsultation onlineConsultation = onlineConsultationRepository.findFirstByOrderNo(orderNo);
        if (null != onlineConsultation) {
            return Boolean.TRUE;
        }
        OrderMain orderMain = orderMainRepository.findById(orderNo).orElse(null);
        if (null == orderMain) {
            return Boolean.FALSE;
        }
        if (!StringUtils.isEmpty(orderMain.getTransactionID())) {
            return Boolean.TRUE;
        }
        ExInfo doctorExInfo = exInfoRepository.findById(orderMain.getDcId()).orElse(null);
        if (null == doctorExInfo) {
            return Boolean.FALSE;
        }
        //医生 问诊量
        doctorExInfo.setInquiry(doctorExInfo.getInquiry() + 1);

        Config doctorConfig = configRepository.findById(orderMain.getDcId()).orElse(null);
        if (null == doctorConfig) {
            return Boolean.FALSE;
        }
        //自动接诊
        Boolean isAuto = Boolean.FALSE;
        //接诊时长 分钟
        int valid = 0;
        //可接诊时间 复诊：24小时；其他：48小时
        int toBeReceive = 48 * 60;
        switch (orderMain.getAType()) {
            case 10:
                valid = doctorConfig.getReferralValid();
                isAuto = doctorConfig.getReferralReception();
                toBeReceive = 24 * 60;
                break;
            case 11:
                valid = doctorConfig.getImgTextValid();
                isAuto = doctorConfig.getImgTextReception();
                break;
            case 12:
                valid = doctorConfig.getPhoneValid();
                isAuto = doctorConfig.getPhoneReception();
                break;
            case 13:
                valid = doctorConfig.getVideoValid();
                isAuto = doctorConfig.getVideoReception();
                break;
            default:
                break;
        }
        Date date = new Date();
        // 预约问诊
        boolean isOversell = false; // 超卖
        if(orderMain.getIsPlantOrder()){
            PlantOrder plant =  plantOrderRepository.findOneDoctorPlant(orderMain.getDcId(), orderMain.getPlantDate(), orderMain.getTimeType());
            int plantNum = plant.getSellCount() + 1;
            orderMain.setPlantNum(plantNum);
            plant.setSellCount(plantNum);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            try {
                long tbeg = date.getTime();
                long tend = sdf1.parse(sdf.format(orderMain.getPlantDate()) + " " + orderMain.getPlantPeriod().split("-")[1]).getTime();
                toBeReceive = (int)((tend - tbeg) / (1000*60)) - 60; // 接诊有效果时间分钟
                if(toBeReceive < 0)
                    toBeReceive = 0;
            } catch (Exception e) {
                return false;
            }

            isOversell = plant.getCountOrder() > 0 && plantNum > plant.getCountOrder();
            if(isOversell){
                toBeReceive = 0;
                plant.setSellCount(plant.getCountOrder());
            }
            plantOrderRepository.save(plant);
        }
        // 医生与患者关系
        DrAndPatients drAndPatients = drAndPatientsRepository.findFirstByDcIdAndPid(orderMain.getDcId(), orderMain.getPid());
        if (null == drAndPatients) {
            // 医生 患者数
            doctorExInfo.setPatient(doctorExInfo.getPatient() + 1);
            drAndPatients = new DrAndPatients();
            drAndPatients.setDcId(orderMain.getDcId());
            drAndPatients.setPid(orderMain.getPid());
            drAndPatients.setCreateTime(date);
            drAndPatients.setLastViStTime(date);
            drAndPatients.setOcId(new Date().getTime());
        } else {
            drAndPatients.setLastViStTime(date);
        }
        drAndPatientsRepository.save(drAndPatients);

        orderMain.setSystemStatus(2L);
        orderMain.setOrderPayTime(date);
        orderMain.setTransactionID(transactionNo);
        orderMain.setOcId(drAndPatients.getOcId());
        orderMain.setToBeReceive(toBeReceive);
        if (isAuto && toBeReceive > 0) {
            orderMain.setReceiveTime(date);
            orderMain.setReceive(valid);
            orderMain.setOcStatus(1);
        }
        orderMainRepository.save(orderMain);

        onlineConsultation = new OnlineConsultation();
        onlineConsultation.setId(IdUtils.generateId());
        onlineConsultation.setOcId(drAndPatients.getOcId());
        onlineConsultation.setOcStatus(0);
        onlineConsultation.setOrderNo(orderNo);
        onlineConsultation.setPid(orderMain.getPid());
        onlineConsultation.setDcId(orderMain.getDcId());
        onlineConsultation.setCreateTime(date);
        onlineConsultation.setUid(orderMain.getClientID());
        onlineConsultation.setAType(orderMain.getAType());
        if (isAuto) {
            onlineConsultation.setOcStatus(1);
            onlineConsultation.setStartTime(date);
            onlineConsultation.setEndTime(DateUtil.offsetMinute(onlineConsultation.getStartTime(), valid));
            onlineConsultation.setLastTime(valid * 60);

            // 总服务数（接诊数）
            doctorExInfo.setService(doctorExInfo.getService() + 1);
            // 接诊率
            doctorExInfo.setReceive(new BigDecimal((double)doctorExInfo.getService() * 100.00 / (double)doctorExInfo.getInquiry()));
        }
        onlineConsultationRepository.save(onlineConsultation);
        exInfoRepository.save(doctorExInfo);

        Boolean finalIsAuto = isAuto;
        CompletableFuture.runAsync(() -> sendNotice(orderMain, finalIsAuto)).thenRunAsync(() -> sendSms(orderMain));
        return Boolean.FALSE;
    }

    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public Boolean RxOrderHandle(String orderNo, String transactionNo) {
        RxMain rxMain = rxMainRepository.findById(orderNo).orElseThrow(null);
        if (null == rxMain) {
            return Boolean.FALSE;
        }
        if (!StringUtils.isEmpty(rxMain.getTransactionID())) {
            return Boolean.TRUE;
        }

        rxMain.setSystemStatus(2);
        rxMain.setOrderPayTime(new Date());
        rxMain.setTransactionID(transactionNo);
        rxMainRepository.save(rxMain);
        return Boolean.FALSE;
    }

    @Transactional(rollbackFor = Exception.class, transactionManager = "jpaTransactionManager")
    public void sendNotice(OrderMain orderMain, Boolean isAuto) {        
        //#region 患者消息
        MsgConfig msgConfig = msgConfigRepository.findById("Client_BuyService").orElse(null);
        if(msgConfig == null)
            return;        
        String token = wxSendMessage.getAccessToken(wxProp.getWxPublicAppId(), wxProp.getWxPublicAppSecret());
        if(token == null)
            return;
        ClientBaseInfo client = clientBaseInfoRepository.findById(orderMain.getClientID()).orElseThrow(() -> new ApiException(1, "未查询到数据"));
        PatientsInfo patient = patientsInfoRepository.findFirstByOrderNo(orderMain.getOrderNo());
        EnumConfig enumConfig = enumConfigRepository.findById(orderMain.getAType().toString()).orElseThrow(() -> new ApiException(1, "未查询到数据"));
        DoctorBaseInfo doctor = doctorBaseInfoRepository.findById(orderMain.getDcId()).orElseThrow(() -> new ApiException(1, "未查询到数据"));
        
        // WxTemplateMessageVo temp = new WxTemplateMessageVo();
        // temp.setTouser(client.getOpenId());
        // temp.setTemplate_id(msgConfig.getTemplateId());
        // temp.setUrl(wxProp.getPurl());
        // Map<String, WxTemplateMessageVo.TemplateData> data = new HashMap<>();
        // data.put("atype", new WxTemplateMessageVo.TemplateData(enumConfig.getName(), ""));
        // data.put("doctorname", new WxTemplateMessageVo.TemplateData(doctor.getName(), ""));
        // data.put("orderno", new WxTemplateMessageVo.TemplateData(orderMain.getOrderNo(), ""));
        // data.put("orderprice", new WxTemplateMessageVo.TemplateData(orderMain.getAskMoney().toString(), ""));
        // SimpleDateFormat sdf =new SimpleDateFormat("yyyy年MM月dd日 HH时mm分");
        // data.put("orderpaytime", new WxTemplateMessageVo.TemplateData(sdf.format(orderMain.getOrderPayTime()), ""));
        // temp.setData(data);
        // boolean sess = wxSendMessage.sendTemplate(temp, token);
        //#endregion

        //#region 医生接诊提醒订阅
        msgConfig = msgConfigRepository.findById("Doctor_Receive").orElse(null);
        if(msgConfig == null)
            return;        
        token = wxSendMessage.getAccessToken(wxProp.getDwxAppletsAppId(), wxProp.getDwxAppletsAppSecret());
        if(token == null)
            return;
        
        WxSubScribeMessageVo stemp = new WxSubScribeMessageVo();
        stemp.setTouser(doctor.getOpenId());
        stemp.setTemplate_id(msgConfig.getTemplateId());
        stemp.setPage("pages/index/index");

        Map<String, WxSubScribeMessageVo.TemplateData> sdata = new HashMap<>();
        sdata.put("thing4", new WxSubScribeMessageVo.TemplateData("【"+patient.getName() +"】患者已成功购买您的【"+enumConfig.getName()+"】服务，请尽快接诊！"));
        sdata.put("thing1", new WxSubScribeMessageVo.TemplateData(patient.getChiefComplaint()));
        stemp.setData(sdata);
        wxSendMessage.sendSubscribeMessage(stemp, token);
        //#endregion
    }

    public void sendSms(OrderMain orderMain) {
        DoctorBaseInfo doctorBaseInfo = doctorBaseInfoRepository.findById(orderMain.getDcId()).orElseThrow(() -> new ApiException(1, "未查询到数据"));
        EnumConfig sysEnumConfig = enumConfigRepository.findById(orderMain.getAType().toString()).orElseThrow(() -> new ApiException(1, "未查询到数据"));
        String typeName = sysEnumConfig.getName();
        MsgConfig sysMsgConfig = msgConfigRepository.findById("Client_ConsultationInfo").orElseThrow(() -> new ApiException(1, "未查询到数据"));
        String templateId = sysMsgConfig.getTemplateId();
        SmsUtils.sendSmsMessage(doctorBaseInfo.getPhone(), Collections.singletonList(typeName), templateId);
    }
}
